package editvois

import (
	"bytes"
	"errors"
	"fmt"
	"html/template"
	"net/http"
	"net/url"
	"strings"

	"gopkg.in/xmlpath.v2"

	"code.google.com/awwwe-browser/auralvm/param"
	"code.google.com/awwwe-browser/auralvm/voisfile"
	"code.google.com/awwwe-browser/data"
	"code.google.com/awwwe-browser/scrub"
	"code.google.com/awwwe-browser/scrub/htmlsoup"
	"code.google.com/awwwe-browser/slurp"
)

// handler for the vois markup editor.
func HandlerEditing(w http.ResponseWriter, r *http.Request) {
	var pdata *PageData
	var err error
	var dirtymarkup []byte
	var contenttype slurp.ContentType
	var scrubber *scrub.Scrubber
	var reader *bytes.Reader
	var tree, node *xmlpath.Node
	var iter *xmlpath.Iter
	var compiledPath *xmlpath.Path
	var ok bool
	var exp string
	var idString string
	var idInt int
	var ids []int
	var editable string
	var editables []string
	var soupnode *htmlsoup.SoupNode
	var insidebody string
	insidebody = data.EmptyString
	pdata = pageDataEditing(r)
	if len(pdata.EditURL) == 0 {
		err = errors.New("You neglected to enter &quot;HTML Web Page URL&quot;")
		HandlerEditorWithError(w, r, err)
		return
	}
	// if can load the web page then set pdata.Body
	// markupbb, err = slurp.SlurpHTMLBodyMarkup(string(pdata.EditURL))
	dirtymarkup, contenttype, err = slurp.SlurpResource(string(pdata.EditURL), param.BrowserCookieJar)
	if err != nil {
		HandlerEditorWithError(w, r, err)
		return
	}
	if contenttype == slurp.ContentTypeHTML {
		// cleanup the dirty markup bytes
		//scrubber = scrub.NewScrubber(dirtymarkup, r.URL.String())
		scrubber = scrub.NewScrubber(dirtymarkup, string(pdata.EditURL))
		scrubber.Scrub()
		reader = bytes.NewReader(scrubber.Bytes())
		tree, err = xmlpath.ParseHTML(reader)
		// get id of the body tag
		if err == nil {
			exp = fmt.Sprintf("/html/body/*/@%s", data.AWWWEAttributeId)
			compiledPath, err = xmlpath.Compile(exp)
		}
		if err != nil {
			HandlerEditorWithError(w, r, err)
			return
		}
		// get ids
		iter = compiledPath.Iter(tree)
		for {
			if iter.Next() {
				node = iter.Node()
				idString = node.String()
				idInt, ok = data.StringToInt(idString)
				if ok {
					ids = append(ids, idInt)
				}
			} else {
				break
			}
		}
		// get the strings of markup
		editables = make([]string, 0, len(ids))
		for _, idInt = range ids {
			soupnode, ok = scrubber.GetNodeFromId(idInt)
			if ok {
				editable = soupnode.String()
				editables = append(editables, editable)
			}
		}
		insidebody = strings.Join(editables, data.EmptyString)
	}
	// add the editable markup from the web page
	pdata.EditableMarkup = template.HTML(insidebody)
	// sub templates
	pdata.editingTemplates()
	// page template
	t, err := template.ParseFiles(fmt.Sprintf("%s/siteLayout.tmpl", Package))
	if err == nil {
		err = t.Execute(w, pdata)
	}
	if err != nil {
		HandlerEditorWithError(w, r, err)
	}
}

// returns the view data for the vois markup editor.
func pageDataEditing(r *http.Request) *PageData {
	var pdata *PageData
	pdata = newPageData(data.EmptyString, "editing")
	pdata.parseEditingData(r)
	pdata.PageTitle = "VOIS Markup Editor"
	pdata.PageClass = "sitePage"
	pdata.HeaderClass = "awwwebrowsersite-header-home"
	pdata.BodyClass = "awwwebrowsersite-home"
	pdata.MainContentClass = "voisEditorContent"
	// css urls
	pdata.CSSURL = template.URL(fmt.Sprintf(homeCssUrl, HomeURL))
	pdata.GeneralCSSURL = template.URL(fmt.Sprintf(generalCssUrl, HomeURL))
	pdata.NavCSSURL = template.URL(fmt.Sprintf(navCssUrl, HomeURL))
	pdata.FormCSSURL = template.URL(fmt.Sprintf(normalFormCssUrl, HomeURL))
	// link class
	pdata.VoisEditorLinkClass += " currentPageLink"
	// error message
	pdata.ErrorMessage = template.HTML(data.EmptyString)

	// javascript
	pdata.setOnClicks(leavingEditorOnClick)
	pdata.VoisEditorOnClick = currentOnClick
	// styles
	pdata.StyleFunc = notHomeStyleFunc
	return pdata
}

// parses the data from the editor view and this view.
func (pdata *PageData) parseEditingData(r *http.Request) {
	var editurl string
	var eurl *url.URL
	var vurl url.URL
	var err error
	var value []string
	var host string
	var ok bool
	var voismarkup string
	var voisurl string
	var voisbb []byte
	var voisstr string
	r.ParseForm()
	// edit_url
	value, ok = r.Form["edit_url"]
	if ok {
		editurl = value[0]
		pdata.EditURL = template.HTMLAttr(editurl)
		eurl, err = url.Parse(editurl)
		if err == nil {
			vurl.Scheme = eurl.Scheme
			vurl.Host = eurl.Host
			vurl.Path = "/vois.xml"
			voisurl = vurl.String()
		}
	} else {
		voisurl = data.EmptyString
	}
	// host
	value, ok = r.Form["host"]
	if ok && len(value[0]) > 0 {
		host = value[0]
		pdata.Host = template.HTMLAttr(host)
		voisurl = host
	} else if len(editurl) > 0 {
		eurl, err = url.Parse(editurl)
		if err == nil {
			pdata.Host = template.HTMLAttr(eurl.Host)
		}
	}
	// vois markup
	value, ok = r.Form["vois_markup"]
	if ok {
		// get the vois markup from the user
		voismarkup = strings.Trim(value[0], data.WhiteSpaceString)
		if len(voismarkup) > 0 {
			pdata.VoisMarkup = template.HTMLAttr(value[0])
			return
		}
	}
	if len(editurl) > 0 {
		// get the vois markup from the editor
		voisbb, err = voisfile.GetVOISBytes(editurl)
		if err == nil {
			voisstr = data.BytesToUTF8String(voisbb)
			pdata.VoisMarkup = template.HTMLAttr(voisstr)
			return
		}
	}
	if len(voisurl) > 0 {
		// try to get the vois markup from the web site
		voisbb, err = slurp.SlurpXMLMarkupUrl(voisurl)
		if err == nil {
			voisstr = data.BytesToUTF8String(voisbb)
			pdata.VoisMarkup = template.HTMLAttr(voisstr)
		}
	}
}

// builds the body and navigation markup for the view data.
// that markup will be inserted into the template.
func (pdata *PageData) editingTemplates() {
	var t *template.Template
	var err error
	var bfr *bytes.Buffer
	// head markup
	t, err = template.ParseFiles(fmt.Sprintf("%s/head.tmpl", Package))
	if err == nil {
		bfr = bytes.NewBuffer(data.EmptyBytes)
		err = t.Execute(bfr, pdata)
		if err == nil {
			pdata.HeadMarkup = template.HTML(bfr.String())
		}
	}
	// body markup
	t, err = template.ParseFiles(fmt.Sprintf("%s/editing.tmpl", Package))
	if err == nil {
		bfr = bytes.NewBuffer(data.EmptyBytes)
		err = t.Execute(bfr, pdata)
		if err == nil {
			pdata.BodyMarkup = template.HTML(bfr.String())
		} else {
			pdata.BodyMarkup = template.HTML(err.Error())
		}
	} else {
		pdata.BodyMarkup = template.HTML(err.Error())
	}
	// navigation markup
	t, err = template.ParseFiles(fmt.Sprintf("%s/navigation.tmpl", Package))
	if err == nil {
		bfr = bytes.NewBuffer(data.EmptyBytes)
		err = t.Execute(bfr, pdata)
		if err == nil {
			pdata.NavigationMarkup = template.HTML(bfr.String())
		}
	}
}
